home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Freeware / Miro 1.0 / Miro_Installer.exe / xulrunner / python / xpcom / components.py < prev    next >
Encoding:
Python Source  |  2007-11-12  |  9.4 KB  |  241 lines

  1. # ***** BEGIN LICENSE BLOCK *****
  2. # Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3. #
  4. # The contents of this file are subject to the Mozilla Public License Version
  5. # 1.1 (the "License"); you may not use this file except in compliance with
  6. # the License. You may obtain a copy of the License at
  7. # http://www.mozilla.org/MPL/
  8. #
  9. # Software distributed under the License is distributed on an "AS IS" basis,
  10. # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11. # for the specific language governing rights and limitations under the
  12. # License.
  13. #
  14. # The Original Code is the Python XPCOM language bindings.
  15. #
  16. # The Initial Developer of the Original Code is
  17. # ActiveState Tool Corp.
  18. # Portions created by the Initial Developer are Copyright (C) 2000, 2001
  19. # the Initial Developer. All Rights Reserved.
  20. #
  21. # Contributor(s):
  22. #   Mark Hammond <MarkH@ActiveState.com> (original author)
  23. #
  24. # Alternatively, the contents of this file may be used under the terms of
  25. # either the GNU General Public License Version 2 or later (the "GPL"), or
  26. # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27. # in which case the provisions of the GPL or the LGPL are applicable instead
  28. # of those above. If you wish to allow use of your version of this file only
  29. # under the terms of either the GPL or the LGPL, and not to allow others to
  30. # use your version of this file under the terms of the MPL, indicate your
  31. # decision by deleting the provisions above and replace them with the notice
  32. # and other provisions required by the GPL or the LGPL. If you do not delete
  33. # the provisions above, a recipient may use your version of this file under
  34. # the terms of any one of the MPL, the GPL or the LGPL.
  35. #
  36. # ***** END LICENSE BLOCK *****
  37.  
  38. # This module provides the JavaScript "components" interface
  39. import xpt
  40. import xpcom, _xpcom
  41. import xpcom.client
  42. import xpcom.server
  43. import types
  44.  
  45. StringTypes = [types.StringType, types.UnicodeType]
  46.  
  47. def _get_good_iid(iid):
  48.     if iid is None:
  49.         iid = _xpcom.IID_nsISupports
  50.     elif type(iid) in StringTypes and len(iid)>0 and iid[0] != "{":
  51.         iid = getattr(interfaces, iid)
  52.     return iid
  53.  
  54. # The "manager" object.
  55. manager = xpcom.client.Component(_xpcom.GetComponentManager(), _xpcom.IID_nsIComponentManager)
  56.  
  57. # The component registrar
  58. registrar = xpcom.client.Component(_xpcom.GetComponentManager(), _xpcom.IID_nsIComponentRegistrar)
  59.  
  60. # The "interfaceInfoManager" object - JS doesnt have this.
  61. interfaceInfoManager = _xpcom.XPTI_GetInterfaceInfoManager()
  62.  
  63. # The serviceManager - JS doesnt have this either!
  64. serviceManager = _xpcom.GetServiceManager()
  65.  
  66. # The "Exception" object
  67. Exception = xpcom.COMException
  68.  
  69. # Base class for our collections.
  70. # It appears that all objects supports "." and "[]" notation.
  71. # eg, "interface.nsISupports" or interfaces["nsISupports"]
  72. class _ComponentCollection:
  73.     # Bases are to over-ride 2 methods.
  74.     # _get_one(self, name) - to return one object by name
  75.     # _build_dict - to return a dictionary which provide access into
  76.     def __init__(self):
  77.         self._dict_data = None
  78.     def keys(self):
  79.         if self._dict_data is None:
  80.             self._dict_data = self._build_dict()
  81.         return self._dict_data.keys()
  82.     def items(self):
  83.         if self._dict_data is None:
  84.             self._dict_data = self._build_dict()
  85.         return self._dict_data.items()
  86.     def values(self):
  87.         if self._dict_data is None:
  88.             self._dict_data = self._build_dict()
  89.         return self._dict_data.values()
  90.     def has_key(self, key):
  91.         if self._dict_data is None:
  92.             self._dict_data = self._build_dict()
  93.         return self._dict_data.has_key(key)
  94.  
  95.     def __len__(self):
  96.         if self._dict_data is None:
  97.             self._dict_data = self._build_dict()
  98.         return len(self._dict_data)
  99.  
  100.     def __getattr__(self, attr):
  101.         if self._dict_data is not None and self._dict_data.has_key(attr):
  102.             return self._dict_data[attr]
  103.         return self._get_one(attr)
  104.     def __getitem__(self, item):
  105.         if self._dict_data is not None and self._dict_data.has_key(item):
  106.             return self._dict_data[item]
  107.         return self._get_one(item)
  108.  
  109. _constants_by_iid_map = {}
  110.  
  111. class _Interface:
  112.     # An interface object.
  113.     def __init__(self, name, iid):
  114.         # Bypass self.__setattr__ when initializing attributes.
  115.         d = self.__dict__
  116.         d['_iidobj_'] = iid # Allows the C++ framework to treat this as a native IID.
  117.         d['name'] = name
  118.     def __cmp__(self, other):
  119.         this_iid = self._iidobj_
  120.         other_iid = getattr(other, "_iidobj_", other)
  121.         return cmp(this_iid, other_iid)
  122.     def __hash__(self):
  123.         return hash(self._iidobj_)
  124.     def __str__(self):
  125.         return str(self._iidobj_)
  126.     def __getitem__(self, item):
  127.         raise TypeError, "components.interface objects are not subscriptable"
  128.     def __setitem__(self, item, value):
  129.         raise TypeError, "components.interface objects are not subscriptable"
  130.     def __setattr__(self, attr, value):
  131.         raise AttributeError, "Can not set attributes on components.Interface objects"
  132.     def __getattr__(self, attr):
  133.         # Support constants as attributes.
  134.         c = _constants_by_iid_map.get(self._iidobj_)
  135.         if c is None:
  136.             c = {}
  137.             i = xpt.Interface(self._iidobj_)
  138.             for c_ob in i.constants:
  139.                 c[c_ob.name] = c_ob.value
  140.             _constants_by_iid_map[self._iidobj_] = c
  141.         if c.has_key(attr):
  142.             return c[attr]
  143.         raise AttributeError, "'%s' interfaces do not define a constant '%s'" % (self.name, attr)
  144.  
  145.  
  146. class _Interfaces(_ComponentCollection):
  147.     def _get_one(self, name):
  148.         try:
  149.             item = interfaceInfoManager.GetInfoForName(name)
  150.         except xpcom.COMException, why:
  151.             # Present a better exception message, and give a more useful error code.
  152.             import nsError
  153.             raise xpcom.COMException(nsError.NS_ERROR_NO_INTERFACE, "The interface '%s' does not exist" % (name,))
  154.         return _Interface(item.GetName(), item.GetIID())
  155.  
  156.     def _build_dict(self):
  157.         ret = {}
  158.         enum = interfaceInfoManager.EnumerateInterfaces()
  159.         while not enum.IsDone():
  160.             # Call the Python-specific FetchBlock, to keep the loop in C.
  161.             items = enum.FetchBlock(500, _xpcom.IID_nsIInterfaceInfo)
  162.             # This shouldnt be necessary, but appears to be so!
  163.             for item in items:
  164.                 ret[item.GetName()] = _Interface(item.GetName(), item.GetIID())
  165.         return ret
  166.  
  167. # And the actual object people use.
  168. interfaces = _Interfaces()
  169.  
  170. del _Interfaces # Keep our namespace clean.
  171.  
  172. #################################################
  173. class _Class:
  174.     def __init__(self, contractid):
  175.         self.contractid = contractid
  176.     def __getattr__(self, attr):
  177.         if attr == "clsid":
  178.             rc = registrar.contractIDToCID(self.contractid)
  179.             # stash it away - it can never change!
  180.             self.clsid = rc
  181.             return rc
  182.         raise AttributeError, "%s class has no attribute '%s'" % (self.contractid, attr)
  183.     def createInstance(self, iid = None):
  184.         import xpcom.client
  185.         try:
  186.             return xpcom.client.Component(self.contractid, _get_good_iid(iid))
  187.         except xpcom.COMException, details:
  188.             import nsError
  189.             # Handle "no such component" in a cleaner way for the user.
  190.             if details.errno == nsError.NS_ERROR_FACTORY_NOT_REGISTERED:
  191.                 raise xpcom.COMException(details.errno, "No such component '%s'" % (self.contractid,))
  192.             raise # Any other exception reraise.
  193.     def getService(self, iid = None):
  194.         return serviceManager.getServiceByContractID(self.contractid, _get_good_iid(iid))
  195.  
  196. class _Classes(_ComponentCollection):
  197.     def __init__(self):
  198.         _ComponentCollection.__init__(self)
  199.     def _get_one(self, name):
  200.         # XXX - Need to check the contractid is valid!
  201.         return _Class(name)
  202.  
  203.     def _build_dict(self):
  204.         ret = {}
  205.         enum = registrar.enumerateContractIDs()
  206.         while enum.hasMoreElements():
  207.             # Call the Python-specific FetchBlock, to keep the loop in C.
  208.             items = enum.fetchBlock(2000, _xpcom.IID_nsISupportsCString)
  209.             for item in items:
  210.                 name = str(item.data)
  211.                 ret[name] = _Class(name)
  212.         return ret
  213.  
  214. classes = _Classes()
  215.  
  216. del _Classes
  217.  
  218. del _ComponentCollection
  219.  
  220. # The ID function
  221. ID = _xpcom.IID
  222.  
  223. # A helper to cleanup our namespace as xpcom shuts down.
  224. class _ShutdownObserver:
  225.     _com_interfaces_ = interfaces.nsIObserver
  226.     def observe(self, service, topic, extra):
  227.         global manager, registrar, classes, interfaces, interfaceInfoManager, _shutdownObserver, serviceManager, _constants_by_iid_map
  228.         manager = registrar = classes = interfaces = interfaceInfoManager = _shutdownObserver = serviceManager = _constants_by_iid_map = None
  229.         xpcom.client._shutdown()
  230.         xpcom.server._shutdown()
  231.  
  232. svc = _xpcom.GetServiceManager().getServiceByContractID("@mozilla.org/observer-service;1", interfaces.nsIObserverService)
  233. # Observers will be QI'd for a weak-reference, so we must keep the
  234. # observer alive ourself, and must keep the COM object alive,
  235. # _not_ just the Python instance!!!
  236. _shutdownObserver = xpcom.server.WrapObject(_ShutdownObserver(), interfaces.nsIObserver)
  237. # Say we want a weak ref due to an assertion failing.  If this is fixed, we can pass 0,
  238. # and remove the lifetime hacks above!  See http://bugzilla.mozilla.org/show_bug.cgi?id=99163
  239. svc.addObserver(_shutdownObserver, "xpcom-shutdown", 1)
  240. del svc, _ShutdownObserver
  241.